package com.yao.context;

import com.yao.util.ReflectionUtils;
import com.yao.util.StringUtils;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletContext;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


@Slf4j
public class AbstractWebApplicationContext implements WebApplicationContext{

    private Map<String,Object> nameObjectMap=new HashMap<>();

    private Map<Class,Object> classObjectMap=new HashMap<>();

    public static String classpathRoot="";
    static {
        String path = AbstractWebApplicationContext.class.getResource("/").getPath();
//        System.out.println(path.replace("/","\\").substring(1));
        classpathRoot=path.replace("/","\\").substring(1);
    }
    public  void listDirectory(File directory){
        if(directory.isDirectory()){
            File[] files = directory.listFiles();
            for (File subfile : files) {
                if(subfile.isFile()){
                    processClassFile(subfile);
                }else{
                    listDirectory(subfile);
                }
            }
        }else{
            processClassFile(directory);
        }
    }

    public  void processClassFile(File file ){
        if(file.getName().endsWith(".class")) {
//            System.out.println(file.getName());
//            System.out.println(file.getPath());
//            System.out.println(file.getAbsolutePath());
            String substring = file.getPath().substring(classpathRoot.length());
            substring = substring.substring(0,substring.length()-6);
            String classWithPackage = substring.replace("\\", ".");
//            System.out.println(classWithPackage);
            try {
                Class<?> aClass = Class.forName(classWithPackage);


                if (ReflectionUtils.isComponent(aClass)) {
                    log.info("{}",Arrays.toString(aClass.getAnnotations()));
                    processComponent(aClass);
                }

            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public  void processComponent(Class cls){
        log.info("add component {}",cls);
        try {
            Object o = cls.getDeclaredConstructor().newInstance();
            this.classObjectMap.put(o.getClass(),o);
            String componentName = ReflectionUtils.componentName(cls);
            if(StringUtils.hasText(componentName)){
                this.nameObjectMap.put(componentName,o);
                return;
            }

        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    void processController(Class cls){}

    public AbstractWebApplicationContext(){
        onRefresh();
        log.info("{}",this.classObjectMap);
        log.info("{}",this.nameObjectMap);
    }

    protected void onRefresh(){
        File file = new File(AbstractWebApplicationContext.class.getResource("/").getPath());
        listDirectory(file);
    }
    @Override
    public Object getBean(String name) {
        return nameObjectMap.get(name);
    }

    @Override
    public <T> T getBean(String name, Class<T> tClass) {
        T nameObj = (T) nameObjectMap.get(name);
        T classObj = (T) classObjectMap.get(tClass);
        if(nameObj==classObj) return (T) nameObj;
        return null;
    }

    @Override
    public ServletContext getServletContext() {
        return (ServletContext) nameObjectMap.get("servletContext");
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        this.nameObjectMap.put("servletContext",servletContext);
        this.classObjectMap.put(ServletContext.class,servletContext);
    }
}
